var Amqp = require('../amqp').Amqp,
    handler = require('../handlers/consumer').Consumer;
/**
 * Work with basic content.
 *
 * The Basic class provides methods that support an industry-standard messaging model.
 *
 * @exports Basic as impl.Basic
 * @class
 * @extends events.EventEmitter
 * @param handler
 */
function Basic(/**handlers.*Channel*/handler){
    var basic = this;
    this.handler = handler;
    /**
     * Confirm the requested qos.
     *
     * This method tells the client that the requested QoS levels could be handled by the server.
     * The requested QoS applies to all active consumers until a new QoS is defined.
     *
     * @name Basic#qos
     * @event
     */
    handler.addListener('Amqp.Basic.QosOk', function(){
        basic.emit('qos');
    });
    /**
     * Confirm a new consumer.
     *
     * The server provides the client with a consumer tag, which is used by the client for methods
     * called on the consumer at a later stage.
     *
     * @name Basic#consume
     * @event
     * @param {Object} args
     * @param {String} args.consumerTag Identifier for the consumer, valid within the current
     *      connection.
     */
    handler.addListener('Amqp.Basic.ConsumeOk', function(frame){
        basic.emit('consume', frame.method.arguments);
    });
    /**
     * Confirm a cancelled consumer.
     *
     * This method confirms that the cancellation was completed.
     *
     * @name Basic#cancel
     * @event
     * @param {Object} args
     * @param {String} args.consumerTag Identifier for the consumer, valid within the current
     *      connection.
     */
    handler.addListener('Amqp.Basic.CancelOk', function(frame){
        basic.emit('cancel', frame.method.arguments);
    });
    /**
     * Return a failed message.
     *
     * This method returns an undeliverable message that was published with the "immediate" flag
     * set, or an unroutable message published with the "mandatory" flag set. The reply code and
     * text provide information about the reason that the message was undeliverable.
     *
     * @name Basic#return
     * @event
     * @param {Object} args
     * @param {Number} args.replyCode The reply code. The AMQ reply codes are defined in
     *      AMQ RFC 011.
     * @param {String} args.replyText The localised reply text.  This text can be logged as an aid
     *      to resolving issues.
     * @param {String} args.exchange The exchange name is a client-selected string that identifies
     *       the exchange for publish methods. Exchange names may consist of any mixture of digits,
     *       letters, and underscores. Exchange names are scoped by the virtual host.
     * @param {String} args.routingKey Specifies the routing key name specified when the message
     *      was published.
     */
    handler.addListener('Amqp.Basic.ReturnOk', function(frame){
        basic.emit('return', frame.method.arguments);
    });
    /**
     * Notify the client of a consumer message.
     *
     * This method delivers a message to the client, via a consumer. In the asynchronous message
     *      delivery model, the client starts a consumer using the Consume method, then the server
     *      responds with Deliver methods as and when messages arrive for that consumer.
     *
     * @name Basic#deliver
     * @event
     * @param {Object} args
     * @param {String} args.consumerTag Identifier for the consumer, valid within the current
     *      connection.
     * @param {Number} args.deliveryTag The server-assigned and channel-specific delivery tag
     * @param {Boolean} redelivered This indicates that the message has been previously delivered
     *      to this or another client.
     * @param {String} args.exchange The exchange name is a client-selected string that identifies
     *      the exchange for publish methods. Exchange names may consist of any mixture of digits,
     *      letters, and underscores. Exchange names are scoped by the virtual host.
     * @param {String} args.routingKey Specifies the routing key name specified when the message
     *      was published.
     * @param {Object} fields
     * @param {String} fields.appId The creating application id.
     * @param {String} fields.clusterId Intra-cluster routing identifier.
     * @param {String} fields.contentEncoding MIME content encoding.
     * @param {String} fields.contentType
     * @param {String} fields.correlationId
     * @param {Nmber} fields.deliveryMode
     * @param {String} fields.expiration
     * @param {Object} fields.headers
     * @param {String} fields.messageId
     * @param {Number} fields.priority
     * @param {String} fields.replyTo
     * @param {Date} fields.timestamp
     * @param {String} fields.type
     * @param {String} fields.userId
     * @param {String} content
     */
    handler.addListener('Amqp.Basic.Deliver', function(frame){
        basic.emit('deliver', frame.method.arguments, frame.header.fields, frame.body);
    });
    /**
     * Provide client with a message.
     *
     * This method delivers a message to the client following a get method. A message delivered by
     *      'get-ok' must be acknowledged unless the no-ack option was set in the get method.
     *
     * @name Basic#get
     * @event
     * @param {Object} args
     * @param {Number} args.deliveryTag The server-assigned and channel-specific delivery tag
     * @param {Boolean} args.redelivered This indicates that the message has been previously
     *      delivered to this or another client.
     * @param {String} args.exchange The exchange name is a client-selected string that identifies
     *       the exchange for publish methods. Exchange names may consist of any mixture of digits,
     *       letters, and underscores. Exchange names are scoped by the virtual host.
     * @param {String} args.routingKey Specifies the routing key name specified when the message
     *      was published.
     * @param {Number} args.messageCount This field reports the number of messages pending on the
     *      queue, excluding the message being delivered. Note that this figure is indicative, not
     *       reliable, and can change arbitrarily as messages are added to the queue and removed by
     *       other clients.
     * @param {Object} fields
     * @param {String} fields.appId The creating application id.
     * @param {String} fields.clusterId Intra-cluster routing identifier.
     * @param {String} fields.contentEncoding MIME content encoding.
     * @param {String} fields.contentType
     * @param {String} fields.correlationId
     * @param {Nmber} fields.deliveryMode
     * @param {String} fields.expiration
     * @param {Object} fields.headers
     * @param {String} fields.messageId
     * @param {Number} fields.priority
     * @param {String} fields.replyTo
     * @param {Date} fields.timestamp
     * @param {String} fields.type
     * @param {String} fields.userId
     * @param {String} content
     */
    handler.addListener('Amqp.Basic.GetOk', function(frame){
        basic.emit('get', frame.method.arguments, frame.header.fields, frame.body);
    });
    /**
     * Indicate no messages available.
     *
     * This method tells the client that the queue has no messages available for the client.
     *
     * @name Basic#empty
     * @event
     * @param {Object} args
     * @param {String} args.clusterId For use by cluster applications, should not be used by client
     *      applications.
     */
    handler.addListener('Amqp.Basic.GetEmpty', function(frame){
        basic.emit('empty', frame.method.arguments);
    });
}
require('sys').inherits(Basic, require('events').EventEmitter);
/**
 * Acknowledge one or more messages.
 *
 * This method acknowledges one or more messages delivered via the Deliver or Get-Ok methods. The
 * client can ask to confirm a single message or a set of messages up to and including a specific
 * message.
 *
 * @param {Object} args
 * @param {Number} args.deliveryTag The server-assigned and channel-specific delivery tag
 * @param {Boolean} args.multiple If set to <code>true</code>, the delivery tag is treated as "up
 *      to and including", so that the client can acknowledge multiple messages with a single
 *      method. If set to <code>false</code>, the delivery tag refers to a single message. If the
 *      multiple field is <code>true</code>, and the delivery tag is zero, tells the server to
 *      acknowledge all outstanding mesages.
 */
Basic.prototype.ack = function(args){
    this.handler.call(Amqp.Class.Basic, Amqp.Class.Basic.Ack, args);
};
/**
 * End a queue consumer.
 *
 * This method cancels a consumer. This does not affect already delivered messages, but it does
 * mean the server will not send any more messages for that consumer. The client may receive an
 * abitrary number of messages in between sending the cancel method and receiving the cancel-ok
 * reply.
 *
 * @param {Object} args
 * @param {String} args.consumerTag Identifier for the consumer, valid within the current
 *      connection.
 * @param {Boolean} args.nowait If set <code>true</code>, the server will not respond to the
 *      method. The client should not wait for a reply method. If the server could not complete the
 *      method it will raise a channel or connection exception.
 */
Basic.prototype.cancel = function(args){
    this.handler.call(Amqp.Class.Basic, Amqp.Class.Basic.Cancel, args);
};
/**
 * Start a queue consumer.
 *
 * This method asks the server to start a "consumer", which is a transient request for messages
 * from a specific queue. Consumers last as long as the channel they were created on, or until the
 * client cancels them.
 *
 * @param {Object} args
 * @param {Number} args.ticket An access ticket granted by the server for a certain set of access
 *      rights within a specific realm. Access tickets are valid within the channel where they were
 *      created, and expire when the channel closes.
 * @param {String} args.queue The queue name identifies the queue within the vhost. Queue names may
 *      consist of any mixture of digits, letters, and underscores.
 * @param {String} args.consumerTag Identifier for the consumer, valid within the current
 *      connection.
 * @param {Boolean} args.noLocal If the field is set <code>true</code> the server will not send
 *      messages to the client that published them.
 * @param {Boolean} args.noAck If this field is set <code>true</code> the server does not expect
 *      acknowledgments for messages. That is, when a message is delivered to the client the server
 *      automatically and silently acknowledges it on behalf of the client. This functionality
 *      increases performance but at the cost of reliability. Messages can get lost if a client
 *      dies before it can deliver them to the application.
 * @param {Boolean} args.exclusive Request exclusive consumer access, meaning only this consumer
 *      can access the queue.
 * @param {Boolean} args.nowait If set <code>true</code>, the server will not respond to the
 *      method. The client should not wait for  a reply method. If the server could not complete
 *      the method it will raise a channel or connection exception.
 */
Basic.prototype.consume = function(args){
    this.handler.call(Amqp.Class.Basic, Amqp.Class.Basic.Consume, args);
};
/**
 * Direct access to a queue.
 *
 * This method provides a direct access to the messages in a queue using  a synchronous dialogue
 * that is designed for specific types of application where synchronous  functionality is more
 * important than performance.
 *
 * @param {Object} args
 * @param {Number} args.ticket An access ticket granted by the server for a certain set of access
 *      rights within a specific realm. Access tickets are valid within the channel where they were
 *      created, and expire when the channel closes.
 * @param {String} args.queue The queue name identifies the queue within the vhost. Queue names may
 *      consist of any mixture of digits, letters, and underscores.
 * @param {Boolean} args.noAck If this field is set <code>true</code> the server does not expect
 *      acknowledgments for messages. That is, when a message is delivered to the client the server
 *      automatically and silently acknowledges it on behalf of the client. This functionality
 *      increases performance but at the cost of reliability. Messages can get lost if a client
 *      dies before it can deliver them to the application.
 */
Basic.prototype.get = function(args){
    this.handler.call(Amqp.Class.Basic, Amqp.Class.Basic.Get, args);
};
/**
 * Publish a message.
 *
 * This method publishes a message to a specific exchange. The message will be routed to queues as
 * defined by the exchange configuration and distributed to any active consumers when the
 * transaction, if any, is committed.
 *
 * @param {Object} args
 * @param {Number} args.ticket An access ticket granted by the server for a certain set of access
 *      rights within a specific realm. Access tickets are valid within the channel where they were
 *      created, and expire when the channel closes.
 * @param {String} args.exchange The exchange name is a client-selected string that identifies the
 *      exchange for publish methods. Exchange names may consist of any mixture of digits, letters,
 *      and underscores. Exchange names are scoped by the virtual host.
 * @param {String} args.routingKey Specifies the routing key for the message. The routing key is
 *      used for routing messages depending on the exchange configuration.
 * @param {Boolean} args.mandatory This flag tells the server how to react if the message cannot be
 *      routed to a queue. If this flag is set, the server will return an unroutable message with a
 *      Return method. If this flag is zero, the server silently drops the message.
 * @param {Boolean} args.immediate This flag tells the server how to react if the message cannot be
 *      routed to a queue consumer immediately. If this flag is set, the server will return an
 *      undeliverable message with a Return method. If this flag is zero, the server will queue the
 *      message, but with no guarantee that it will ever be consumed.
 * @param {Object} fields
 * @param {String} fields.appId The creating application id.
 * @param {String} fields.clusterId Intra-cluster routing identifier.
 * @param {String} fields.contentEncoding MIME content encoding.
 * @param {String} fields.contentType
 * @param {String} fields.correlationId
 * @param {Nmber} fields.deliveryMode
 * @param {String} fields.expiration
 * @param {Object} fields.headers
 * @param {String} fields.messageId
 * @param {Number} fields.priority
 * @param {String} fields.replyTo
 * @param {Date} fields.timestamp
 * @param {String} fields.type
 * @param {String} fields.userId
 * @param {String} body
 */
Basic.prototype.publish = function(args, fields, body){
    this.handler.call(Amqp.Class.Basic, Amqp.Class.Basic.Publish, args, fields, body);
};
/**
 * Specify quality of service.
 *
 * This method requests a specific quality of service. The QoS can be specified for the current
 * channel or for all channels on the connection. The particular properties and semantics of a
 * qos method always depend on the content class semantics. Though the qos method could in
 * principle apply to both peers, it is currently meaningful only for the server.
 *
 * @param {Object} args
 * @param {Number} args.prefetchSize The client can request that messages be sent in advance so
 *      that when the client finishes processing a message, the following message is already held
 *      locally, rather than needing to be sent down the channel. Prefetching gives a performance
 *      improvement. This field specifies the prefetch window size in octets. The server will send
 *      a message in advance if it is equal to or smaller in size than the available prefetch size
 *      (and also falls into other prefetch limits). May be set to zero, meaning "no specific
 *      limit", although other prefetch limits may still apply. The prefetch-size is ignored if the
 *      no-ack option is set.
 * @param {Number} args.prefetchCount Specifies a prefetch window in terms of whole messages. This
 *      field may be used in combination with the prefetch-size field; a message will only be sent
 *      in advance if both prefetch windows (and those at the channel and connection level) allow
 *      it. The prefetch-count is ignored if the no-ack option is set.
 * @param {Boolean} args.global By default the QoS settings apply to the current channel only. If
 *      this field is set, they are applied to the entire connection.
 */
Basic.prototype.qos = function(args){
    this.handler.call(Amqp.Class.Basic, Amqp.Class.Basic.Publish, args);
};
/**
 * Redeliver unacknowledged messages.
 *
 * This method is only allowed on non-transacted channels. This method asks the broker to redeliver
 * all unacknowledged messages on a specifieid channel. Zero or more messages may be redelivered.
 *
 * @param {Object} arg
 * @param {Boolean} args.requeue If this field is <code>false</code>, the message will be
 *      redelivered to the original recipient. If this field is <code>true</code>, the server will
 *      attempt to requeue the message, potentially then delivering it to an alternative
 *      subscriber.
 */
Basic.prototype.recover = function(args){
    this.handler.call(Amqp.Class.Basic, Amqp.Class.Basic.Recover, args);
};
/**
 * Reject an incoming message.
 *
 * This method allows a client to reject a message. It can be used to interrupt and cancel large
 * incoming messages, or return untreatable messages to their original queue.
 *
 * @param {Object} args
 * @param {Number} args.deliveryTag The server-assigned and channel-specific delivery tag.
 * @param {Boolean} args.requeue If this field is <code>false</code>, the message will be
 *      discarded. If this field is <code>true</code>, the server will attempt to requeue the
 *      message.
 */
Basic.prototype.reject = function(args){
    this.handler.call(Amqp.Class.Basic, Amqp.Class.Basic.Reject, args);
};
exports.Basic = Basic;
